﻿using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.XPath;

namespace XModify
{
    public class XmlNSParse
    {
        public static XmlNS Parse(string xmlContent, XmlNamespaceManager xmlNamespaceManager)
        {
            XmlNS additionNS = null;

            StringReader stringReader = new StringReader(xmlContent);
            XPathDocument xPathDocument = new XPathDocument(stringReader);
            XPathNavigator xPathVanigator = xPathDocument.CreateNavigator();

            XPathNodeIterator list = xPathVanigator.Select("//namespace::*[name() != 'xml'][not(../../namespace::*=.)]");
            int c = 0;
            while (list.MoveNext())
            {
                XPathNavigator nsNode = list.Current;
                if (nsNode.NodeType == XPathNodeType.Namespace)
                {
                    string ns = nsNode.Value;

                    // get the prefix - it's either empty or not
                    string origPrefix = nsNode.LocalName;

                    // make sure the prefix is unique
                    bool empty = false;
                    int dupes = 0;
                    string actualPrefix = origPrefix;

                    while (actualPrefix == "")
                    {
                        if (!empty)
                        {
                            empty = true;
                        }

                        actualPrefix = (origPrefix == "")
                                ? String.Format("ns{0}", c++)
                                : String.Format("{0}-{1}", origPrefix, dupes++);
                    }

                    if (empty)
                    {
                        additionNS = new XmlNS();
                        additionNS.Prefix = actualPrefix;
                        additionNS.NS = ns;
                    }

                    if (!xmlNamespaceManager.HasNamespace(actualPrefix))
                    {
                        xmlNamespaceManager.AddNamespace(actualPrefix, ns);
                    }
                }
            }


            return additionNS;
        }

        public static string NewXPath(string xPath, XmlNS xmlNS)
        {
            if (xmlNS == null)
            {
                return xPath;
            }

            xPath = FixupXpathExpressionWithDefaultNamespace(xPath, xmlNS.Prefix);
            return xPath;
        }

        private static string FixupXpathExpressionWithDefaultNamespace(string xPath, string prefix)
        {
            string s = xPath;
            s = Regex.Replace(s, "^(?!::)([^/:]+)(?=/)", prefix + ":$1");                             // beginning
            s = Regex.Replace(s, "/([^/:\\*\\(]+)(?=[/\\[])", "/" + prefix + ":$1");                  // segment
            s = Regex.Replace(s, "::([A-Za-z][^/:*]*)(?=/)", "::" + prefix + ":$1");                  // axis specifier
            s = Regex.Replace(s, "\\[([A-Za-z][^/:*\\(]*)(?=[\\[\\]])", "[" + prefix + ":$1");        // within predicate
            s = Regex.Replace(s, "/([A-Za-z][^/:\\*\\(]*)(?!<::)$", "/" + prefix + ":$1");               // end
            s = Regex.Replace(s, "^([A-Za-z][^/:]*)$", prefix + ":$1");                               // edge case
            s = Regex.Replace(s, "([A-Za-z][-A-Za-z]+)\\(([^/:\\.,\\(\\)]+)(?=[,\\)])", "$1(" + prefix + ":$2"); // xpath functions

            return s;
        } 
    }
}
